package com.study.spring.retry.retryByCustom;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.util.concurrent.ExecutorService;

/**
 * @author
 * @date 2021年11月16日 22:01
 * @description
 */
public class FastRetryStrategy implements RetryStrategy, ApplicationContextAware {


    private Retry retry;

    private RetryTask retryTask;


    private ApplicationContext applicationContext;

    private ExecutorService executorService;


    @Override

    public void initArgs(Retry retry, RetryTask retryTask) {
        this.retry = retry;
        this.retryTask = retryTask;
    }

    @Override
    public void retryTask() {

        if (!FastRetryStrategy.class.equals(retry.strategy())) {
            System.err.println("error retry strategy");
            return;
        }
        String[] listenerBeansName = applicationContext.getBeanNamesForType(retry.listener());

        RetryListener retryListener = null;
        if (listenerBeansName != null && listenerBeansName.length > 0) {
            retryListener = applicationContext.getBean(retry.listener());
        }

        Class<? extends Throwable>[] exceptionClasses = retry.value();
        RetryListener finalRetryListener = retryListener;

        executorService.submit(new Runnable() {
            @Override
            public void run() {
                for (int i = 1; i <= retry.maxAttempts(); i++) {
                    int finalI = i;
                    try {
                        retryTask.doTask();
                        retryTask.setRetrySuccess();
                        return;
                    } catch (Throwable e) {

                        for (Class<? extends Throwable> exceptionClass : exceptionClasses) {
                            if (e.getClass().equals(exceptionClass) || e.getClass().isInstance(exceptionClass)) {
                                if (finalRetryListener != null) {
                                    finalRetryListener.notifyObserver();
                                }

                                System.err.println("[FastRetryStrategy] retry again,attempt's time is " + finalI + ",tims is " + System.currentTimeMillis());

                                try {
                                    Thread.sleep(retry.delay());
                                } catch (InterruptedException interruptedException) {
                                    interruptedException.printStackTrace();
                                }
                                continue;
                            }
                        }


                        e.printStackTrace();
                    }


                }
            }
        });

    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
        this.setExecutorService((ExecutorService) applicationContext.getBean("retryThreadPool"));
    }

    public void setExecutorService(ExecutorService executorService) {
        this.executorService = executorService;
    }

    public ExecutorService getExecutorService() {
        return this.executorService;
    }
}
